#include "fileModel.h"

FileModel::FileModel(const std::string& path,const std::string& file) : objfile(file),path(path){
	obj_parser.error_callback(	std::tr1::bind(&FileModel::error_callback,
								this ,std::tr1::placeholders::_1,std::tr1::placeholders::_2));

	obj_parser.geometric_vertex_callback( 	std::tr1::bind(&FileModel::geometric_vertex_callback,
											this ,std::tr1::placeholders::_1,std::tr1::placeholders::_2,std::tr1::placeholders::_3) );

	obj_parser.vertex_normal_callback(	std::tr1::bind(&FileModel::vertex_normal_callback,
										this ,std::tr1::placeholders::_1,std::tr1::placeholders::_2,std::tr1::placeholders::_3) );

	obj_parser.material_library_callback( 	std::tr1::bind(&FileModel::material_library_callback,
											this ,std::tr1::placeholders::_1) );

	obj_parser.material_name_callback(	std::tr1::bind(&FileModel::material_group_change,
										this ,std::tr1::placeholders::_1) );

	obj_parser.texture_vertex_callback(	std::tr1::bind(&FileModel::texture_vertex_callback,
										this ,std::tr1::placeholders::_1,std::tr1::placeholders::_2) );

	obj_parser.face_callbacks(	NULL,NULL,NULL,
								std::tr1::bind(&FileModel::triangular_face_callback,
								this ,std::tr1::placeholders::_1,std::tr1::placeholders::_2,std::tr1::placeholders::_3),
								NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);


	mtl_parser.error_callback(	std::tr1::bind(&FileModel::error_callback,
								this ,std::tr1::placeholders::_1,std::tr1::placeholders::_2));

	mtl_parser.material_name_callback(	std::tr1::bind(&FileModel::material_name_change,
										this ,std::tr1::placeholders::_1) );

	mtl_parser.ambient_reflectivity_callback(	std::tr1::bind(&FileModel::ambient_reflectivity_rgb_callback,
												this ,std::tr1::placeholders::_1 ,std::tr1::placeholders::_2,std::tr1::placeholders::_3),
												NULL,NULL);

	mtl_parser.diffuse_reflectivity_callback(	std::tr1::bind(&FileModel::diffuse_reflectivity_rgb_callback,
												this ,std::tr1::placeholders::_1 ,std::tr1::placeholders::_2 ,std::tr1::placeholders::_3),
												NULL,NULL);

	mtl_parser.specular_reflectivity_callback(	std::tr1::bind(&FileModel::specular_reflectivity_rgb_callback,
												this ,std::tr1::placeholders::_1 ,std::tr1::placeholders::_2 ,std::tr1::placeholders::_3),
												NULL,NULL);

	mtl_parser.specular_exponent_callback(	std::tr1::bind(&FileModel::specular_exponent_callback,
											this ,std::tr1::placeholders::_1));

	mtl_parser.dissolve_factor_callback(	std::tr1::bind(&FileModel::dissolve_factor_callback,
											this ,std::tr1::placeholders::_1));

	mtl_parser.texture_map_callbacks(	NULL,
										std::tr1::bind(&FileModel::texture_map_diffuse_reflectivity_callback,
										this ,std::tr1::placeholders::_1,std::tr1::placeholders::_2),
										NULL,NULL,NULL,NULL,NULL,NULL,NULL);

	this->type = GL_TRIANGLES;
}

FileModel::~FileModel(){
}

void FileModel::loadModel(){
	if(!obj_parser.parse(path+objfile))
		throw FileModelException("No se pudo utilizar el archivo <" + this->objfile + ">");
}


void FileModel::ambient_reflectivity_rgb_callback(obj::float_type r,obj::float_type g,obj::float_type b){
	_materials[current]->ambient(r,g,b);
}

void FileModel::diffuse_reflectivity_rgb_callback(obj::float_type r,obj::float_type g,obj::float_type b){
	_materials[current]->diffuse(r,g,b);
}

void FileModel::specular_reflectivity_rgb_callback(obj::float_type r,obj::float_type g,obj::float_type b){
	_materials[current]->specular(r,g,b);
}

void FileModel::specular_exponent_callback(obj::float_type ns){
	_materials[current]->shininess(ns);
}

void FileModel::dissolve_factor_callback(obj::float_type d){
	_materials[current]->transparency(d);
}

void FileModel::texture_map_diffuse_reflectivity_callback(const obj::options_type& options,const std::string& filename){
	_materials[current]->texture(filename);
}

void FileModel::material_name_change(const std::string& name){
	this->current = name;
	this->_materials.insert(std::make_pair(name,new Material()));
	_materials[current]->path(this->path);
}

// Obj parser functions
void FileModel::material_group_change(const std::string& name){
	this->current = name;
	this->_groups.push_back(new ModelGroup(*_materials[current]));
}

void FileModel::material_library_callback(const std::string& name){
	this->mtlfile = name;
	if(!mtl_parser.parse(path+name))
		throw FileModelException("No se pudo utilizar el archivo <" + this->mtlfile + ">");
}

void FileModel::geometric_vertex_callback(obj::float_type x, obj::float_type y, obj::float_type z){
	_vertices.push_back(x);
	_vertices.push_back(y);
	_vertices.push_back(z);
}

void FileModel::vertex_normal_callback(obj::float_type x, obj::float_type y, obj::float_type z){
	_normals.push_back(x);
	_normals.push_back(y);
	_normals.push_back(z);
}

void FileModel::texture_vertex_callback(obj::float_type x, obj::float_type y){
	_textures.push_back(x);
	_textures.push_back(y);
}

void FileModel::triangular_face_callback(const obj::index_3_tuple_type& t1, const obj::index_3_tuple_type& t2, const obj::index_3_tuple_type& t3){
	this->_groups.back()->_faces.push_back(std::tr1::get<0>(t1)-1);
	this->_groups.back()->_faces.push_back(std::tr1::get<1>(t1)-1);
	this->_groups.back()->_faces.push_back(std::tr1::get<2>(t1)-1);
	this->_groups.back()->_faces.push_back(std::tr1::get<0>(t2)-1);
	this->_groups.back()->_faces.push_back(std::tr1::get<1>(t2)-1);
	this->_groups.back()->_faces.push_back(std::tr1::get<2>(t2)-1);
	this->_groups.back()->_faces.push_back(std::tr1::get<0>(t3)-1);
	this->_groups.back()->_faces.push_back(std::tr1::get<1>(t3)-1);
	this->_groups.back()->_faces.push_back(std::tr1::get<2>(t3)-1);
}

void FileModel::error_callback(unsigned int line,const std::string& message){
	std::stringstream msg;
	msg << "obj_filename= " << this->objfile << " line= " << line << " " << message << std::endl;
	throw FileModelException(msg.str());
}
